package com.zhao.customer.util;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * 数据库工具类
 * 提供了获取连接的公共方法
 * 提供了做增删改的公共方法
 * 提供了做查询操作的公共方法
 * 提供了关闭所有数据库资源的公共方法
 * @author Administrator
 *
 */
public class DBUtil {

    private static String className;
    private static String url;
    private static String user;
    private static String password;

    //静态代码块完成了属性文件的读取和驱动的加载
    static{
        try {
            //1、把数据库连接参数参数
            Properties pops = new Properties();
            //把jdbc.properties中的数据库连接参数读取出来存放在Properties对象中
            pops.load(DBUtil.class.getResourceAsStream("/jdbc.properties"));
            //从Properties对象按照键获取对应的属性值
            className=pops.getProperty("jdbc.mysql.className");
            url = pops.getProperty("jdbc.mysql.url");
            user = pops.getProperty("jdbc.mysql.user");
            password = pops.getProperty("jdbc.mysql.password");

            //2、加载数据库驱动
            Class.forName(className);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * 公共的获取数据库连接的方法
     * @return -获取到数据库连接
     * @throws SQLException
     */
    public static Connection getConnection() throws SQLException{
        Connection conn = DriverManager.getConnection(url, user, password);
        return conn;
    }

    /**
     * 释放数据库资源
     * @param rs -结果集对象，如果不需要关闭该资源传入null
     * @param stmt -语句对象，如果不需要关闭该资源传入null
     * @param conn -连接对象，如果不需要关闭该资源传入null
     * @throws SQLException
     */
    public static void close(ResultSet rs, Statement  stmt,Connection  conn) throws SQLException{
        if(rs!=null){
            rs.close();
        }
        if(stmt!=null){
            stmt.close();
        }
        if(conn!=null){
            conn.close();
        }
    }

    /**
     * 增删改公共通用方法
     * @param sql -增删改对应的sql语句
     * @return
     */
    public static int update(String sql){
        return update(sql,null);
    }

    /**
     * 增删改的公共通用方法
     * @param sql -增删改对应的sql语句
     * @param args -为占位符设置的参数，如果不需要参数可以传递null或者数据长度为0数组
     * @return
     */
    public static int update(String sql,Object[] args){
        Connection conn = null;
        PreparedStatement ps = null;
        int rows = 0;

        try {
            conn = getConnection();
            ps = conn.prepareStatement(sql);
            //如果数组不为null且长度大于0说明sql语句中有？占位符
            if(args!=null && args.length>0){
                //需要将数组中的元素设置分别设置给占位符
                for(int i=0;i<args.length;i++){
                    ps.setObject(i+1, args[i]);
                }
            }

            rows = ps.executeUpdate();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            try {
                close(null, ps, conn);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        return rows;
    }


    /**
     * 通用的查询方法
     * @param sql -查询语句
     * @return -将查询到每行数据的多列存放到Map集合中，以列名作为键，以列值作为值，将保持一行中多列数据的Map集合放在List集合中返回
     */
    public static List<Map<String,String>> query(String sql){
        return query(sql,new Object[]{});
    }

    /**
     * 查询通用方法
     * @param sql -执行查询的sql语句
     * @param args -为sql语句中占位符?设置的值数组，该数组允许为null值，如果为null或者数组长度为0则视为sql参数中不包含?占位符
     * @return -将查询到每行数据的多列存放到Map集合中，以列名作为键，以列值作为值，将保持一行中多列数据的Map集合放在List集合中返回
     */
    public static List<Map<String,String>> query(String sql,Object... args){
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        List<Map<String,String>> list = new ArrayList<Map<String,String>>();

        try {
            conn = getConnection();
            ps = conn.prepareStatement(sql);
            //为sql语句中的?占位符设置值
            if(args!=null && args.length>0){
                for(int i=0;i<args.length;i++){
                    ps.setObject(i+1, args[i]);
                }
            }
            rs = ps.executeQuery();
            //查询结果的中包含几列，每一列的数据类型 每一列的列名这些信息都封装到ResultSetMetaData对象中
            ResultSetMetaData rsmd = rs.getMetaData();
            //获取到查询结果中包含了几列
            int count = rsmd.getColumnCount();

            while(rs.next()){
                //取出当前行的每一列 因为该方法是通用方法，所以在定义方法无法获取用户需要查询多少列数据，在这想要完成这个功能，需要知道我们这次查询查询几列，每一列的列名是什么
                HashMap<String, String> map = new HashMap<String, String>();
                for(int i=1;i<=count;i++){
                    //取出每一列的列名
                    String cname = rsmd.getColumnLabel(i);
                    //取出每一列的值
                    String cvalue = rs.getString(cname);
                    map.put(cname, cvalue);
                }
                //把这一行数据放置到List集合中
                list.add(map);
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            try {
                close(rs,ps,conn);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return list;
    }
}
